#include "triangle.h"

triangle::triangle(): primitive()
{
	pointA.set(0.0,0.0,0.0);
	pointB.set(1.0,0.0,0.0);
	pointC.set(0.0,1.0,0.0);
}
triangle::triangle(point cen, point cen1, point cen2, point cen3, double mul, const char* _name): primitive(_name)
{
	vector3 ABvec(cen1, cen2);
	vector3 ACvec(cen1, cen3);
	ABvec *= mul;
	ACvec *= mul;
	pointA = cen;
	pointB = ABvec.movePoint(cen2);
	pointC = ACvec.movePoint(cen3);

}
triangle::triangle(point cen, point cen1, point cen2, point cen3, double mul)
{
	vector3 ABvec(cen1, cen2);
	vector3 ACvec(cen1, cen3);
	ABvec *= mul;
	ACvec *= mul;
	pointA = cen;
	pointB = ABvec.movePoint(cen2);
	pointC = ACvec.movePoint(cen3);
}
triangle::triangle(point cen, point cen1, point cen2, point cen3)
{
	vector3 ABvec(cen1, cen2);
	vector3 ACvec(cen1, cen3);
	pointA = cen;
	pointB = ABvec.movePoint(cen2);
	pointC = ACvec.movePoint(cen3);
}
triangle::triangle(point cen1, point cen2, point cen3, double mul, const char* _name): primitive(_name)
{
	vector3 ABvec(cen1, cen2);
	vector3 ACvec(cen1, cen3);
	ABvec *= mul;
	ACvec *= mul;
	pointA = cen1;
	pointB = ABvec.movePoint(cen2);
	pointC = ACvec.movePoint(cen3);
}
triangle::triangle(point cen1, point cen2, point cen3, double mul)
{
	vector3 ABvec(cen1, cen2);
	vector3 ACvec(cen1, cen3);
	ABvec *= mul;
	ACvec *= mul;
	pointA = cen1;
	pointB = ABvec.movePoint(cen2);
	pointC = ACvec.movePoint(cen3);
}
triangle::triangle(point cen1, point cen2, point cen3, const char* _name): primitive(_name)
{
	pointA = cen1;
	pointB = cen2;
	pointC = cen3;
}
triangle::triangle(point cen1, point cen2, point cen3)
{
	pointA = cen1;
	pointB = cen2;
	pointC = cen3;
}
triangle::triangle(point cen, vector3 vec1, vector3 vec2, double mul, const char* _name): primitive(_name)
{
	vec1 *= mul;
	vec2 *= mul;
	pointA = cen;
	pointB = vec1.movePoint(cen);
	pointC = vec2.movePoint(cen);
}
triangle::triangle(point cen, vector3 vec1, vector3 vec2, double mul)
{
	vec1 *= mul;
	vec2 *= mul;
	pointA = cen;
	pointB = vec1.movePoint(cen);
	pointC = vec2.movePoint(cen);
}
triangle::triangle(point cen, vector3 vec1, vector3 vec2)
{
	pointA = cen;
	pointB = vec1.movePoint(cen);
	pointC = vec2.movePoint(cen);
}
triangle::~triangle()
{
	
}
void triangle::getTriangleFromXML(std::ifstream &file)
{
	char line[MAX_LENGTH];
	file.getline(line, MAX_LENGTH);
	std::string temp(line);
	std::string nazwaWezla;

	unsigned int i(0);

	while (nazwaWezla!="/triangle")
	{
		file.getline(line, MAX_LENGTH);
		temp.clear();
		temp.append(line);
		nazwaWezla.clear();

		i=0;
		while(temp[i] == 9 || temp[i] == 32)
			++i;
		if(temp[i] == '<')
		{
			std::string nazwaWezlaKoniec;
			std::string zawartoscWezla;
			++i;
			while(temp[i] != '>')
			{
				nazwaWezla.push_back(temp[i]);
				++i;
			}
			if(nazwaWezla == "surfacematerial")
			{
				nazwaWezla.clear();	
				file.getline(line, MAX_LENGTH);
				std::string temp(line);
				i = 0;
				zawartoscWezla.clear();
				while(temp[i] == 9 || temp[i] == 32)
					++i;
				++i;
				while(temp[i] != ' ')
				{
					zawartoscWezla.push_back(temp[i]);
					++i;
				}
				if (zawartoscWezla == "material")
				{
					zawartoscWezla.clear();
					while(temp[i] == 32)
						++i;
					while(temp[i] != '=')
					{
						zawartoscWezla.push_back(temp[i]);
						++i;
					}
					if (zawartoscWezla == "type")
					{
						i+=2;
						zawartoscWezla.clear();
						while(temp[i] != 34)
						{
							zawartoscWezla.push_back(temp[i]);
							++i;
						}
						if (zawartoscWezla == "none")
						{
							matNone tempMat;
							tempMat.getMaterialFromXML(file);
							setMaterial(new matNone(tempMat));
						}
						else if (zawartoscWezla == "lambert")
						{
							matLambert tempMat;
							tempMat.getMaterialFromXML(file);
							setMaterial(new matLambert(tempMat));
						}
						else if (zawartoscWezla == "phong")
						{
							matPhong tempMat;
							tempMat.getMaterialFromXML(file);
							setMaterial(new matPhong(tempMat));
						}
						else if (zawartoscWezla == "blinn")
						{
							matBlinn tempMat;
							tempMat.getMaterialFromXML(file);
							setMaterial(new matBlinn(tempMat));
						}
						else if (zawartoscWezla == "orenNayer")
						{
							matOrenNayer tempMat;
							tempMat.getMaterialFromXML(file);
							setMaterial(new matOrenNayer(tempMat));
						}
						else if (zawartoscWezla == "mirror")
						{
							matGlass tempMat;
							tempMat.getMaterialFromXML(file);
							setMaterial(new matGlass(tempMat));
						}
						else if (zawartoscWezla == "glass")
						{
							matGlass tempMat;
							tempMat.getMaterialFromXML(file);
							setMaterial(new matGlass(tempMat));
						}
					}
				}
			}
			else if(nazwaWezla == "name")
			{
				++i;
				while(temp[i] != '<')
				{
					zawartoscWezla.push_back(temp[i]);
					++i;
				}
				++i;
				while(temp[i] != '>')
				{
					nazwaWezlaKoniec.push_back(temp[i]);
					++i;
				}
				if(nazwaWezlaKoniec == "/name")
					this->name.append(zawartoscWezla.c_str());
				continue;
			}
			else if(nazwaWezla == "name /")
			{
				continue;
			}
			else if(nazwaWezla == "pointA")
			{
				point tempPoint;
				texcoords tempTexCoords;
				tempPoint.getPointFromXML(file);
				tempTexCoords.getTexCoordsFromXML(file);
				pointA = tempPoint;
				pointATexCoord = tempTexCoords;
				continue;
			}
			else if(nazwaWezla == "pointB")
			{
				point tempPoint;
				texcoords tempTexCoords;
				tempPoint.getPointFromXML(file);
				tempTexCoords.getTexCoordsFromXML(file);
				pointB = tempPoint;
				pointBTexCoord = tempTexCoords;
				continue;
			}
			else if(nazwaWezla == "pointC")
			{
				point tempPoint;
				texcoords tempTexCoords;
				tempPoint.getPointFromXML(file);
				tempTexCoords.getTexCoordsFromXML(file);
				pointC = tempPoint;
				pointCTexCoord = tempTexCoords;
				continue;
			}
		}
	}
}
double triangle::maxX()
{
	return std::max(pointA.x, std::max(pointB.x, pointC.x));
}
double triangle::minX()
{
	return std::min(pointA.x, std::min(pointB.x, pointC.x));
}
double triangle::maxY()
{
	return std::max(pointA.y, std::max(pointB.y, pointC.y));
}
double triangle::minY()
{
	return std::min(pointA.y, std::min(pointB.y, pointC.y));
}
double triangle::maxZ()
{
	return std::max(pointA.z, std::max(pointB.z, pointC.z));
}
double triangle::minZ()
{
	return std::min(pointA.z, std::min(pointB.z, pointC.z));
}
void triangle::setATexCoords(texcoords tex)
{
	pointATexCoord = tex;
}
void triangle::setBTexCoords(texcoords tex)
{
	pointBTexCoord = tex;	
}
void triangle::setCTexCoords(texcoords tex)
{
	pointCTexCoord = tex;
}
void triangle::setTexCoords(texcoords texA, texcoords texB, texcoords texC)
{
	pointATexCoord = texA;
	pointBTexCoord = texB;
	pointCTexCoord = texC;
}
void triangle::copyTriangle(triangle TheOneToCopyFrom)
{
	pointA = TheOneToCopyFrom.pointA;
	pointB = TheOneToCopyFrom.pointB;
	pointC = TheOneToCopyFrom.pointC;
}
point triangle::getCenter()
{
	return pointA;
}
int triangle::intersect( ray& Ray, intersection& inter)
{
	point colisionCoords;
	if(!planeIntersect(Ray, colisionCoords))
		return 0;
	else
	{
		vector3 x;
		vector3 normal(getNormal(point()));
		vector3 fa(pointA, colisionCoords);
		vector3 fb(pointB, colisionCoords);
		vector3 fc(pointC, colisionCoords);
		x = fa.cross2(fb);
		if(x.dot(normal)>PLUS_ZERO)
			return false;
		else
		{
			x = fb.cross2(fc);
			if(x.dot(normal)>PLUS_ZERO)
				return false;
			else
			{
				x = fc.cross2(fa);
				if(x.dot(normal)>PLUS_ZERO)
					return 0;
				else
				{
					inter.colisionCoords = colisionCoords;
					inter.objectID = ObjectID;
					inter.objectNormal = normal;
					vector3 distanceHelper(Ray.getDesrination(), colisionCoords);
					inter.distance = distanceHelper.width();
					getTextureCoords(inter);
					return 1;
				}
			}
		}
	}
}
bool triangle::isInShade( ray& Ray)
{
	point colisionCoords;
	if(!planeIntersect(Ray, colisionCoords))
		return false;
	else
	{
		vector3 x;
		vector3 normal(getNormal(point()));
		vector3 fa(pointA, colisionCoords);
		vector3 fb(pointB, colisionCoords);
		vector3 fc(pointC, colisionCoords);
		x = fa.cross2(fb);
		if(x.dot(normal)>PLUS_ZERO)
			return false;
		else
		{
			x = fb.cross2(fc);
			if(x.dot(normal)>PLUS_ZERO)
				return false;
			else
			{
				x = fc.cross2(fa);
				if(x.dot(normal)>PLUS_ZERO)
					return false;
				else
				{
					vector3 lightDistaceHelper(Ray.getOrigin(),Ray.getDesrination());
					vector3	triangleDistanceHelper(Ray.getOrigin(),colisionCoords);
					if(lightDistaceHelper <= triangleDistanceHelper)
						return false;
					else
						return true;
				}
			}
		}
	}
}
bool triangle::planeIntersect(ray& Ray, point& colisionPoint)
{
	vector3 normal(getNormal(point()));
	double d(-normal.dot(vector3(pointA)));

	vector3 rayOrigin;
	double NorDotLo = normal.dot(vector3(Ray.getOrigin()));
	double NorDotLd = normal.dot(Ray.getDirection());
	if (NorDotLd == 0.0)
		return false;
	double distance = ( -d - NorDotLo ) / ( NorDotLd );
	if(distance <= 0.0)
		return false;
	
	vector3 temporaryHelper = Ray.getDirection()*distance;
	colisionPoint = temporaryHelper.movePoint(Ray.getOrigin());

	vector3 planeSizeChecker(colisionPoint, pointA);
	vector3 ABvec(pointA, pointB);
	vector3 ACvec(pointA, pointC);
	if(planeSizeChecker > ABvec && planeSizeChecker > ACvec)
		return false;
	else
		return true;
}
vector3 triangle::getNormal(point inPoint)
{
	vector3 ABvec(pointA, pointC);
	vector3 ACvec(pointA, pointB);
	ABvec.cross(ACvec);
	ABvec.normalize();
	return ABvec;
}
void triangle::getTextureCoords(intersection& inter)
{
	inter.texCoords.setTexCoords(0.0, 0.0);
}